import type { Directive, App } from 'vue';
import { createVNode, render } from 'vue';
import { ElTooltip } from 'element-plus';

const elMap = new Map();
const listenerEnterMap = new Map();
const listenerLeaveMap = new Map();
const listenerClickMap = new Map();
let tooltipInstance: any;

const ellTooltip: Directive<HTMLElement> = {
  mounted: (el, binding) => {
    const { value, arg } = binding;
    let content = '';
    if (typeof value === 'string') {
      content = value;
    } else {
      content = value?.content;
    }

    if (!content) {
      content = el.innerText;
    }
    // 加上超出...样式
    // 举例 v-ellTooltip:2
    if (arg && arg === '2') {
      el.classList.add('g-ells-2');
    } else {
      el.style.overflow = 'hidden';
      el.style.textOverflow = 'ellipsis';
      el.style.whiteSpace = 'nowrap';
    }
    const onMouseLeave = () => {
      // console.log('onMouseLeave', el);
      const elApp = elMap.get(el);
      if (!elApp) return;
      tooltipInstance.component.props.visible = false;
    };

    const onClick = (e: Event) => {
      const elApp = elMap.get(e.target);
      console.log('onClick e', e.target, el, elApp);
      if (!elApp) return;
      tooltipInstance.component.props.visible = false;
    };

    const onMouseEnter = () => {
      if (isOverflow(el)) {
        console.log('tooltipInstance', tooltipInstance, el);
        if (!tooltipInstance) {
          const mountNode = document.createElement('div');
          document.body.appendChild(mountNode);
          tooltipInstance = createVNode(ElTooltip, {
            visible: true,
            content: value?.fetch ? el.innerText : content,
            virtualTriggering: true,
            virtualRef: el
          });
          render(tooltipInstance, mountNode);
        } else {
          console.log('tooltipInstance-innerText', el.innerText, content, value?.fetch);

          tooltipInstance.component.props.content = value?.fetch ? el.innerText : content;
          tooltipInstance.component.props.virtualRef = el;
          tooltipInstance.component.props.visible = true;
        }
        elMap.set(el, true);
      }
    };
    listenerEnterMap.set(el, [['mouseenter', onMouseEnter]]); // 用于拓展后续的监听
    listenerLeaveMap.set(el, [['mouseleave', onMouseEnter]]); // 用于拓展后续的监听
    el.addEventListener('mouseenter', onMouseEnter);
    el.addEventListener('mouseleave', onMouseLeave);

    if (value?.clickHide) {
      el.addEventListener('click', onClick);
      listenerClickMap.set(el, [['click', onClick]]);
    }
  },
  unmounted: el => {
    elMap.clear();
    listenerEnterMap.clear();
    listenerLeaveMap.clear();
    const eventsEnter = listenerEnterMap.get(el) || [];
    const eventsLeave = listenerLeaveMap.get(el) || [];
    const eventsClick = listenerClickMap.get(el) || [];
    if ([...eventsEnter, ...eventsLeave, ...eventsClick].length) {
      [...eventsEnter, ...eventsLeave, ...eventsClick].forEach(([name, event]: any) =>
        el.removeEventListener(name, event)
      );
    }
  }
};

export function setupEllTooltip(app: App): void {
  app.directive('ellTooltip', ellTooltip);
}

function isOverflow(target: HTMLElement) {
  const scrollWidth = target.scrollWidth;
  const offsetWidth = target.offsetWidth;
  const scrollHeight = target.scrollHeight;
  const offsetHeight = target.offsetHeight;
  const range = document.createRange();
  range.setStart(target, 0);
  range.setEnd(target, target.childNodes.length);
  const rangeWidth = range.getBoundingClientRect().width;
  const padding =
    (parseInt(getElStyleAttr(target, 'paddingLeft'), 10) || 0) +
    (parseInt(getElStyleAttr(target, 'paddingRight'), 10) || 0);
  return (
    rangeWidth + padding > target.offsetWidth + 1 ||
    scrollWidth > offsetWidth ||
    scrollHeight > offsetHeight + 1
  );
}

function getElStyleAttr(element: Element, attr: any) {
  const styles = window.getComputedStyle(element);
  return styles[attr];
}
